package table.model.rowModel;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

import javax.swing.table.AbstractTableModel;

import table.model.SimpleColumn;


public class SortedRowModel {
	
	ArrayList<Row> rows = new ArrayList<Row>();
	ArrayList<ColumnDirection> dirs = new ArrayList<ColumnDirection>();
	AbstractTableModel data = null;
	
	ColumnDirection curSortingColumnBy = null;
	
	public SortedRowModel(AbstractTableModel data) {
		this.data = data;
	}
	
	public void fireTableDataChanged() {
		if(rows.size()!=data.getRowCount()) {
			rows.clear();
			for(int i=0;i<data.getRowCount();i++)
	        {
	            Row curRow = new Row(i);
	            addRow(curRow);
	        }
		}
        resort();
	}
	
	public void fireTableStructureChanged() {
		dirs.clear();
		restoreState();
	}
	
	public void addColDir(ColumnDirection newColDir) {
		dirs.add(newColDir);
	}
	
	public void addRow(Row newRow) {
		rows.add(newRow);
		newRow.setRowModel(this);
	}

	public int sortRowValuesAt(int row1, int row2) {
        Object o1 = data.getValueAt(row1, curSortingColumnBy.getColumn().getModelIndex()); //TODO
        Object o2 = data.getValueAt(row2, curSortingColumnBy.getColumn().getModelIndex());//TODO

        int comparison = 0; 
        
        // Define null less than everything, except null.
        if (o1 == null && o2 == null) {
            comparison = 0;
        } else if (o1 == null) {
            comparison = -1;
        } else if (o2 == null) {
            comparison = 1;
        } else {
            comparison = getComparator(curSortingColumnBy.getColumn().getModelIndex()).compare(o1, o2);//TODO
        }
        if (comparison != 0) {
            return curSortingColumnBy.getDirection() == ColumnDirection.DESCENDING ? -comparison : comparison;
        }
		return 0;
	}

    public boolean isSorting() {
        return dirs.size() != 0;
    }
    
	public Row getRow(int row) {
		return rows.get(row);
	}
	
	@SuppressWarnings("unchecked")
	private Comparator<Object> getComparator(int column) {
		Class columnClass = data.getColumnClass(column);
		if(columnClass.isAssignableFrom(Comparator.class)) {
			return new ComparableComp();
		}
		return new LexicalComp();
	}
	
    private ColumnDirection getColumnDirection(SimpleColumn column) {
        for (ColumnDirection curDir: dirs) {
            if (curDir.getColumn() == column) {
                return curDir;
            }
        }
        return ColumnDirection.EMPTY_DIRECTIVE;
    }

    public int getSortingStatus(SimpleColumn column) {
        return getColumnDirection(column).getDirection();
    }

	public void setSortingStatus(SimpleColumn column, int status) {
        ColumnDirection directive = getColumnDirection(column);
        if (directive != ColumnDirection.EMPTY_DIRECTIVE) {
            dirs.remove(directive);
        }
        if (status != ColumnDirection.NOT_SORTED) {
            dirs.add(new ColumnDirection(column, status));
        }
        if(status == ColumnDirection.NOT_SORTED) {
        	restoreState();
        }
	}
	
	@SuppressWarnings("unchecked")
	private void resort() {
        for (ColumnDirection curDir : dirs) {
        	curSortingColumnBy = curDir;
        	Collections.sort(rows);
        }
	}
	
	private void restoreState() {
		for(int i=0;i<rows.size();i++) {
			for(Row curRow: rows) {
				if(curRow.getModelIndex()==i) {
					rows.remove(curRow);
					rows.add(i,curRow);
					break;
				}
			}
		}
	}
}
